/********************************************************************************
 * Copyright 2009 The Robotics Group, The Maersk Mc-Kinney Moller Institute,
 * Faculty of Engineering, University of Southern Denmark
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ********************************************************************************/

#ifndef RWLIBS_SIMULATION_SIMULATEDCAMERA_HPP
#define RWLIBS_SIMULATION_SIMULATEDCAMERA_HPP

/**
   @file SimulatedCamera.hpp
*/

#include <rw/core/Ptr.hpp>
#include <rw/sensor/Camera.hpp>
#include <rw/sensor/Image.hpp>
#include <rwlibs/simulation/SimulatedSensor.hpp>

#include <string>

namespace rw { namespace sensor {
    class CameraModel;
}}    // namespace rw::sensor

namespace rwlibs { namespace simulation {
    class FrameGrabber;

    /** @addtogroup simulation */
    /* @{ */

    /**
     * @brief The SimulatedCamera class makes it posible to use virtual camera
     * sensors by using different framegrapper implementations.
     *
     * The SimulatedCamera implements the camera interface though the setting of
     * framerate has no meaning to the virtual camera since no timing is done in
     * this implementation.
     */
    class SimulatedCamera : public SimulatedSensor
    {
      public:
        //! @brief Smart pointer type for a SimulatedCamera.
        typedef rw::core::Ptr< SimulatedCamera > Ptr;

        /**
         * @brief creates a simulated pinhole camera,
         * @param name [in] name of sensor
         * @param fov [in] field of view for the camera.
         * @param frame [in] frame to which the camera is attached
         * @param frameGrabber [in] the frameGrabber from which this Camera should grab images
         */
        SimulatedCamera (const std::string& name, double fov, rw::kinematics::Frame* frame,
                         rw::core::Ptr< FrameGrabber > frameGrabber);

        /**
         * @brief constructor
         * @param model [in] the model and info of the camera
         * @param frameGrabber [in] the frameGrabber from which this Camera should grab
         * images.
         */
        SimulatedCamera (rw::core::Ptr< rw::sensor::CameraModel > model,
                         rw::core::Ptr< FrameGrabber > frameGrabber);

        /**
         * @brief destructor
         */
        virtual ~SimulatedCamera ();

        /**
         * @copydoc rw::sensor::Camera::initialize
         */
        bool initialize ();

        /**
         * @copydoc rw::sensor::Camera::start
         */
        bool start ();

        /**
         * @copydoc rw::sensor::Camera::stop
         */
        void stop ();

        /**
         * @copydoc rw::sensor::Camera::acquire
         */
        void acquire ();

        /**
         * @copydoc rw::sensor::Camera::isImageReady
         */
        bool isImageReady ();

        /**
         * @copydoc rw::sensor::Camera::getImage
         */
        const rw::sensor::Image* getImage ();

        /**
         * @copydoc rw::sensor::Camera::getFrameRate
         */
        double getFrameRate ();

        /**
         * @copydoc rw::sensor::Camera::setFrameRate
         */
        void setFrameRate (double framerate);

        /**
         * @copydoc rw::sensor::Camera::getWidth
         */
        virtual unsigned int getWidth () const;

        /**
         * @copydoc rw::sensor::Camera::getHeight
         */
        virtual unsigned int getHeight () const;

        /**
         * @copydoc SimulatedSensor::update
         */
        void update (const Simulator::UpdateInfo& info, rw::kinematics::State& state);

        /**
         * @copydoc SimulatedSensor::reset
         */
        void reset (const rw::kinematics::State& state) {}

        rw::sensor::Sensor::Ptr getSensor () { return _csensor; }

        /**
         * @brief Get the camera sensor.
         * @return the sensor.
         */
        rw::sensor::Camera::Ptr getCameraSensor () { return _csensor; }

      private:
        void acquire (char* imgData);

      private:
        double _frameRate;
        double _dtSum;
        rw::core::Ptr< FrameGrabber > _frameGrabber;
        bool _isAcquired;
        bool _started;
        bool _initialized;

        rw::sensor::Camera::Ptr _csensor;
    };

    /* @} */
}}    // namespace rwlibs::simulation

#endif    // end include guard
